pub use super::utils::*;
use crate::utils::singleton::SingleInit;
use crate::{flush_thread_pool, submit, utils};
use rusqlite::ffi::sqlite3_stmt;
use rusqlite::{Connection, Statement, ToSql};
use std::cmp::min;
use std::collections::HashSet;
use std::fs::{File, OpenOptions};
use std::future::pending;
use std::io::{BufRead, BufReader, Write};
use std::mem::take;
use std::ops::Add;
use std::path::Path;
use std::rc::Rc;
use std::sync::{Arc, Mutex, Once};
use std::vec;
use walkdir::{DirEntry, WalkDir};

// pub fn init_simple_log() {
//     let config = ConfigBuilder::new()
//         .set_time_format_custom(format_description!(
//             "[year]-[month]-[day] [hour]:[minute]:[second]"
//         ))
//         .build();
//     CombinedLogger::init(vec![
//         TermLogger::new(
//             LevelFilter::Info,
//             config.clone(),
//             TerminalMode::Mixed,
//             ColorChoice::Auto,
//         ),
//         WriteLogger::new(
//             LevelFilter::Info,
//             config,
//             File::create("rust_web.log").unwrap(),
//         ),
//     ])
//     .unwrap();
// }

#[allow(non_snake_case)]
#[macro_export]
macro_rules! log_info {
($($args:expr),*) => {{
    $crate::utils::SimplePool::single_mut().lock().unwrap().execute(move ||{info!("{}",format_args!($($args),*));});
}};
}

#[allow(non_snake_case)]
#[macro_export]
macro_rules! log_warn {
($($args:expr),*) => {{
    $crate::utils::SimplePool::single_const().execute(move ||{warn!("{}",format_args!($($args),*));});
}};
}

#[allow(non_snake_case)]
#[macro_export]
macro_rules! log_error {
($($args:expr),*) => {{
    $crate::utils::SimplePool::single_const().execute(move ||{error!("{}",format_args!($($args),*));});
}};
}

pub struct ThreadSafeShare<T>(pub *const T);

impl<T: Clone> ThreadSafeShare<T> {
    pub fn get(self) -> T {
        unsafe { (&*self.0).clone() }
    }
}

unsafe impl<T> Send for ThreadSafeShare<T> {}

impl<T> Clone for ThreadSafeShare<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Copy for ThreadSafeShare<T> {}

pub fn build_trait_index_test(source_dir: &str, scope: &str) {
    // 获取所有的rs结尾源文件信息
    let mut rust_src_file_path: Vec<String> = Vec::new();
    WalkDir::new(source_dir)
        .into_iter()
        .filter_entry(|entry| {
            (entry.file_type().is_dir()
                && !(entry.file_name().eq_ignore_ascii_case("test")
                    || entry.file_name().eq_ignore_ascii_case("benches")))
                || (entry.file_type().is_file()
                    && entry.file_name().to_str().unwrap().ends_with(".rs"))
        })
        .for_each(|e| {
            if e.as_ref().unwrap().file_type().is_file() {
                rust_src_file_path.push(e.unwrap().path().to_str().unwrap().to_string());
            }
        });
    //   解析所有的源文件信息
    // let shared_file_stream = Arc::new(Mutex::new(create_new_file(
    //     "src/repos",
    //     "new_traits_index.txt",
    // )));
    // let share = ThreadSafeShare(&shared_file_stream);

    let arc = Arc::new(Mutex::new(HashSet::new()));
    let share = ThreadSafeShare(&arc);
    for path in rust_src_file_path {
        // let clone_var =  ||{concurrent_file_stream.clone()};
        // let clone_file_stream = concurrent_file_stream.clone();
        submit!({
            BufReader::new(File::open(path).unwrap())
                .lines()
                .for_each(|line| {
                    if let Some(tmp) = utils::str_between_join(
                        line.unwrap().as_str(),
                        &["impl", "for", "{"],
                        "@%@",
                    ) {
                        share.get().lock().unwrap().insert(tmp);
                        // .write_all((tmp + "\n").as_bytes())
                        // .expect("failed written!");
                    }
                });
        });
    }
    flush_thread_pool!();

    let drip_str = |test_str: &str| {
        let mut strs = String::new();
        let mut pos = 0;
        let mut cnt = 0;
        while pos < test_str.len() {
            let mut check: isize = 0;
            match (&test_str[pos..]).find(|e| {
                if e == '>' {
                    check = -1;
                    true
                } else { false }
            } || {
                if e == '<' {
                    check = 1;
                    true
                } else { false }
            }) {
                None => {
                    strs.push_str(&test_str[pos..]);
                    break;
                }
                Some(mut tmp) => {
                    tmp +=pos;
                    if cnt == 0 { strs.push_str(&test_str[pos..tmp]) }
                    cnt += check;
                    pos = tmp + 1;
                }
            };
        }
        strs.trim().to_string()
    };

    insert_traits_to_local_dat(
        Arc::try_unwrap(arc)
            .unwrap()
            .into_inner()
            .unwrap()
            .into_iter()
            .map(|e| {
                let vec = e.split("@%@").collect::<Vec<_>>();
                (drip_str(vec[0]), vec[0].to_string(), vec[1].to_string())
            })
            .collect::<Vec<_>>()
            .as_slice(),
        scope,
    );
}

pub fn insert_traits_to_local_dat(traits_map: &[(String, String, String)], scope: &str) {
    let connection = Connection::open("src/repos/t_index.dat").unwrap();
    //     connection
    //         .execute(r#"
    //         create table if not exists  main.TRAIT_INDEX
    // (
    //     ID         INTEGER         not null
    //         constraint TRAIT_INDEX_pk
    //             primary key autoincrement,
    //     TRAIT      TEXT,
    //     CLASS_NAME TEXT,
    //     SCOPE      TEXT default '' not null
    // );
    //
    // create index if not exists main.TRAIT_INDEX_CLASS_NAME_index
    //     on main.TRAIT_INDEX (CLASS_NAME);
    //
    // create index if not exists main.TRAIT_INDEX_SCOPE_index
    //     on main.TRAIT_INDEX (SCOPE);
    //
    // create index if not exists main.TRAIT_INDEX_TRAIT_index
    //     on main.TRAIT_INDEX (TRAIT);
    //         delete from TRAIT_INDEX where 1=1;"#, [])
    //         .unwrap();
    let sql_base = "insert into TRAIT_INDEX (SCOPE,SPECIFIC, TRAIT, CLASS_NAME) VALUES".to_string();
    const SPLIT_GAP: usize = 500;
    let group = traits_map.len() / SPLIT_GAP;
    let mut params_field_vec = Vec::new();

    for each in 0..=group {
        for (x1, x2, x3) in
            &traits_map[each * SPLIT_GAP..min((each + 1) * SPLIT_GAP, traits_map.len())]
        {
            params_field_vec.push(format!(
                "('{}','{}','{}','{}')",
                scope,
                x1.replace("'", "''"),
                x2.replace("'", "''"),
                x3.replace("'", "''")
            ));
        }
        let sql = sql_base.clone() + params_field_vec.join(",").as_str();
        connection.execute(sql.as_str(), []).unwrap();

        params_field_vec.clear();
    }
}

#[test]
pub fn test_index() {
    // build_trait_index_test(
    //     r#"C:\Users\admin\.rustup\toolchains\stable-x86_64-pc-windows-gnu\lib\rustlib\src"#,"INNER_SCOPE"
    // );
    build_trait_index_test(
        r#"C:\Users\admin\.cargo\registry\src\github.com-1ecc6299db9ec823"#,"OUTER_SCOPE"
    );
}

pub fn find_file(dir: &str, filename: &str) -> Option<String> {
    let mut dir_iter = WalkDir::new(dir).max_depth(5).into_iter();
    while let Some(Ok(entry)) = dir_iter.next() {
        let path = entry.path();
        if path.is_file() && path.to_str().unwrap().contains(filename) {
            return Some(String::from(path.to_str().unwrap()));
        }
    }
    None
}

pub fn find_file_all(dir: &str, filename: &str) -> Option<Vec<String>> {
    let mut dir_iter = WalkDir::new(dir).max_depth(5).into_iter();
    let mut vec = Vec::new();
    while let Some(Ok(entry)) = dir_iter.next() {
        let path = entry.path();
        if path.is_file() && (path.to_str().unwrap().contains(filename) || filename.len() == 0) {
            vec.push(String::from(path.to_str().unwrap()));
        }
    }
    Some(vec)
}

pub fn distinct_file_content_by_line(file_name: &str) {
    let file_path = Path::new(file_name);
    let mut vec: Vec<String>;
    if file_path.is_dir() {
        vec = find_file_all(file_path.to_str().unwrap(), "").unwrap();
    } else {
        vec = vec![String::from(file_path.to_str().unwrap())];
    }
    for e in vec {
        let mut set = HashSet::new();
        for l in BufReader::new(File::open(e.clone()).unwrap()).lines() {
            set.insert(l.unwrap());
        }
        File::create(e.clone()).unwrap();
        let mut wf = OpenOptions::new()
            .read(true)
            .write(true)
            .append(true)
            .open(e)
            .unwrap();
        for x in set.into_iter() {
            wf.write_all(x.add("\n").as_bytes());
        }
    }
}
